package gush
{
	import flare.data.DataSet;
	import flare.data.DataSource;
	import flare.physics.Spring;
	import flare.vis.Visualization;
	import flare.vis.controls.DragControl;
	import flare.vis.data.Data;
	import flare.vis.data.DataSprite;
	import flare.vis.data.EdgeSprite;
	import flare.vis.data.NodeSprite;
	import flare.vis.operator.layout.ForceDirectedLayout;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.net.URLLoader;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	import flash.utils.Dictionary;

	public class GushF extends Sprite
	{
		private var WIDTH:uint = 760 - 1;
		private var HEIGHT:uint = 430 - 1;
		//		
		private var vis:Visualization;
		private var data:Data;
		private var map:Dictionary;
		public function GushF()
		{
			//draw border
			graphics.clear();
			graphics.lineStyle(1,0x000000);
			graphics.drawRect(0,0,WIDTH,HEIGHT);
			map = new Dictionary();
		}
		
		//then gush
		private function getNameFromTextField():void{
			var txt:TextField = new TextField();
			txt.type = TextFieldType.INPUT;
			txt.text = "Enter Fanfou id";
			txt.textColor = 0x999999;
			txt.border = true;
			txt.multiline = false;
			txt.height = 18;
			txt.width = 150;
			txt.x = WIDTH/2 - txt.width/2;
			txt.y = HEIGHT/2;
			txt.addEventListener(FocusEvent.FOCUS_IN,function(evt:FocusEvent):void{
				txt.text="";
				txt.textColor = 0x333333;
			});
			txt.addEventListener(KeyboardEvent.KEY_UP,function(evt:KeyboardEvent):void{
				if(13==evt.keyCode){
					gush(txt.text);
					removeChild(txt);
				}
			});
			addChild(txt);
		}
		
		public function gush(name:String = null):void{
			if(null == name){
				getNameFromTextField();
				return;
			}
			if(null == vis){//first time use vis
				data = new Data();
				vis = new Visualization(data);
//				vis.bounds = new Rectangle(0, 0, WIDTH, HEIGHT);
				var bigN:Number = 2;			
				vis.bounds = new Rectangle(-WIDTH*bigN, -HEIGHT*bigN, WIDTH*(bigN*2+1), HEIGHT*(bigN*2+1));
				vis.graphics.lineStyle(20,0x000000);
				vis.graphics.drawRect(vis.bounds.x,vis.bounds.y,vis.bounds.width,vis.bounds.height);
	            var op:ForceDirectedLayout=new ForceDirectedLayout(true);
	            op.restLength = function(e:EdgeSprite):Number {
					return op.defaultSpringLength * e.props.restLength;
				}
	            op.tension = function(e:EdgeSprite):Number {
					var s:Spring = Spring(e.props.spring);
					var n:Number = Math.max(s.p1.degree, s.p2.degree);
					return op.defaultSpringTension * e.props.tension / Math.sqrt(n) ;
				}
				op.mass = function(d:DataSprite):Number {
					return op.defaultParticleMass * d.props.mass;
				}
	            vis.continuousUpdates = true;
	            op.parameters={
					"simulation.dragForce.drag": 0.1,
					defaultParticleMass: 3,
					defaultSpringLength: 40,
					defaultSpringTension: 0.02
				};
	            vis.operators.add(op);
				vis.update();
				addChild(vis);
				vis.addEventListener(MouseEvent.MOUSE_DOWN,function(evt:MouseEvent):void{
					if(evt.target is Visualization)
						vis.startDrag();
				});
				vis.addEventListener(MouseEvent.MOUSE_UP,function(evt:MouseEvent):void{
					if(evt.target is Visualization)
						vis.stopDrag();
				});
	            vis.controls.add(new DragControl(NodeSprite));
			}//end if null == vis
			//
			//get the node from which to gush
			if(null == map[name]){
				map[name] = createNode(data, name);
				map[name].props.expand = true;
				map[name].x=WIDTH/2;
				map[name].y=HEIGHT/2;
			}
			map[name].alpha = 1;
			//curl neighbors
//			var feed:String = "http://gush-friends.appspot.com/wangyuantao.json";
			var feed:String = "http://gush-friends.appspot.com/ff?url=http://api.fanfou.com/statuses/user_timeline/"+name+".json";
			var ds:DataSource = new DataSource(feed, "json");
            var loader:URLLoader = ds.load();
            loader.addEventListener(Event.COMPLETE, function(evt:Event):void {
                var ds:DataSet = loader.data as DataSet;
                if(null == ds){
                	//auth error
                	trace("auth error:"+name);
                	return;
                }
                var fs:Array = new Array();
                for(var i:uint=0;i<ds.nodes.data.length;i++){
                	var json:Object = ds.nodes.data[i];
                	var towhom:String = json.in_reply_to_user_id;
                	if(towhom){
                		if(fs[towhom]){
                			fs[towhom].push(json)
                		}else{
                			fs[towhom]=[json];
                		}		                
	                }
                }
                for(var guy:String in fs){
                	if(null == map[guy]){
                		map[guy] = createNode(data, guy, fs[guy]);
                		map[guy].x = map[name].x + 30*(Math.random()-0.5);
                		map[guy].y = map[name].y + 30*(Math.random()-0.5);
                	}
		            var e:EdgeSprite = data.addEdgeFor(map[name], map[guy]);
		            e.props.jsons = fs[guy];
		            e.props.tension = tensionFun(e.props.jsons);
		            e.props.restLength = restLengthFun(e.props.jsons);
		            e.alpha = edgeAlphaFun(e.props.tension);
                }
            });	
		}
		
		private function createNode(data:Data, name:String,jsons:Array = null):NodeSprite{
			var node:NodeSprite = data.addNode();
			var txt:TextField = new TextField();
			txt.text = jsons?jsons[0].in_reply_to_screen_name:name;
			txt.selectable = false;
			txt.autoSize = TextFieldAutoSize.LEFT;
			txt.height = 12;
			txt.x=2;
			txt.y=2;
			//
			node.addChild(txt);
			node.props.expand = false;// has not been expanded
			node.props.fanfouid = name;
			node.props.mass = 1;//jsons?jsons[0].user.followers_count:500;
			node.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void{
				if(node.props.expand)
					return;
				node.props.expand = true;
			//	trace(node.props.fanfouid);
				gush(node.props.fanfouid);
			//	detail(node.props.fanfouid);
			});
			node.addEventListener(MouseEvent.MOUSE_OVER,function(evt:MouseEvent):void{
				node.fillColor &= 0xFF0000FF;
			});
			node.addEventListener(MouseEvent.MOUSE_OUT,function(evt:MouseEvent):void{
				node.fillColor |= 0x00CCCC00;
			});
			node.alpha = 0.3;
			return node;
		}
		
		private function tensionFun(jsons:Array):Number{
			var rs:Number = 0;
			var t0:Number = new Date().getTime();
			for(var i:uint=0;i<jsons.length;i++){
				var t1:Number = Date.parse(jsons[i].created_at);
				var dt:Number = (t0 - t1)/1000/3600/24/7;
				rs += Math.exp(-dt);
			}
			return rs;
		}
		private function restLengthFun(jsons:Array):Number{
			var t0:Number = new Date().getTime();
			var t1:Number = Date.parse(jsons[0].created_at);
			var dt:Number = (t0 - t1)/1000/3600/24/45;
			return Math.pow(1+dt,1.5);
		}
		private function edgeAlphaFun(tension:Number):Number{
			//0.1-0.4;
			return 0.2 + 0.3 * Math.pow((tension / 20),0.25);
		}
	}
}